package com.fishingwithme.android.data.local

import androidx.datastore.core.DataStore
import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.core.booleanPreferencesKey
import androidx.datastore.preferences.core.doublePreferencesKey
import androidx.datastore.preferences.core.edit
import androidx.datastore.preferences.core.longPreferencesKey
import androidx.datastore.preferences.core.stringPreferencesKey
import com.fishingwithme.android.data.model.CityLocation
import com.fishingwithme.android.data.model.LoginUserDto
import com.fishingwithme.android.data.model.User
import com.google.gson.Gson
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
import javax.inject.Inject
import javax.inject.Singleton

@Singleton
class PreferencesManager @Inject constructor(
    private val dataStore: DataStore<Preferences>
) {

    companion object {
        // Keys matching WeChat Mini Program's storage keys
        private val LOGIN_USER = stringPreferencesKey("loginUser")
        private val ACCESS_TOKEN = stringPreferencesKey("access_token")

        // Theme preference
        private val THEME_MODE = stringPreferencesKey("theme_mode")
        const val THEME_FOLLOW_SYSTEM = "follow_system"
        const val THEME_LIGHT = "light"
        const val THEME_DARK = "dark"

        // Location and City storage keys
        private val CURRENT_LATITUDE = doublePreferencesKey("current_latitude")
        private val CURRENT_LONGITUDE = doublePreferencesKey("current_longitude")
        private val CURRENT_CITY_CODE = stringPreferencesKey("current_city_code")
        private val CURRENT_CITY_NAME = stringPreferencesKey("current_city_name")
        private val LOCATION_UPDATE_TIME = longPreferencesKey("location_update_time")

        private val CITY_LOCATION = stringPreferencesKey("city_location")

    }

    private val json = Gson()

    // User login information
    suspend fun saveLoginUser(userJson: LoginUserDto) {
        dataStore.edit { preferences ->
            preferences[LOGIN_USER] = json.toJson(userJson)
        }
    }

    suspend fun saveLoginUser(userJson: User) {
        dataStore.edit { preferences ->
            preferences[LOGIN_USER] = json.toJson(userJson)
        }
    }

    fun getLoginUser(): Flow<String?> {
        return dataStore.data.map { preferences ->
            preferences[LOGIN_USER]
        }
    }

    fun getLoginUserObj(): Flow<User?> {
        return dataStore.data.map { preferences ->
            val userJson: String? = preferences[LOGIN_USER]

            userJson?.let {
                try {
                    json.fromJson(it, User::class.java)
                } catch (e: Exception) {
                    null
                }
            }
        }
    }


    suspend fun clearLoginUser() {
        dataStore.edit { preferences ->
            preferences.remove(LOGIN_USER)
        }
    }

    // Access token
    suspend fun saveAccessToken(token: String) {
        dataStore.edit { preferences ->
            preferences[ACCESS_TOKEN] = token
        }
    }

    fun getAccessToken(): Flow<String?> {
        return dataStore.data.map { preferences ->
            preferences[ACCESS_TOKEN]
        }
    }

    suspend fun clearAccessToken() {
        dataStore.edit { preferences ->
            preferences.remove(ACCESS_TOKEN)
        }
    }


    suspend fun saveCityLocation(cityLocation: CityLocation) {
        dataStore.edit { preferences ->
            preferences[CITY_LOCATION] = json.toJson(cityLocation)
        }
    }

    fun getCurrentCityLocation(): Flow<CityLocation?> {
        return dataStore.data.map { preferences ->
            val clJson: String? = preferences[CITY_LOCATION]

            clJson?.let {
                try {
                    json.fromJson(it, CityLocation::class.java)
                } catch (e: Exception) {
                    null
                }
            }
        }
    }

    // Location and City storage
    suspend fun saveLocation(latitude: Double, longitude: Double) {
        dataStore.edit { preferences ->
            preferences[CURRENT_LATITUDE] = latitude
            preferences[CURRENT_LONGITUDE] = longitude
            preferences[LOCATION_UPDATE_TIME] = System.currentTimeMillis()
        }
    }

    suspend fun saveCity(cityCode: String, cityName: String? = null) {
        dataStore.edit { preferences ->
            preferences[CURRENT_CITY_CODE] = cityCode
            cityName?.let { preferences[CURRENT_CITY_NAME] = it }
        }
    }


    // Generic boolean storage
    suspend fun saveBoolean(key: String, value: Boolean) {
        val prefsKey = booleanPreferencesKey(key)
        dataStore.edit { preferences ->
            preferences[prefsKey] = value
        }
    }

    fun getBoolean(key: String, defaultValue: Boolean = false): Flow<Boolean> {
        val prefsKey = booleanPreferencesKey(key)
        return dataStore.data.map { preferences ->
            preferences[prefsKey] ?: defaultValue
        }
    }

    // Theme preferences
    suspend fun saveThemeMode(themeMode: String) {
        dataStore.edit { preferences ->
            preferences[THEME_MODE] = themeMode
        }
    }

    fun getThemeMode(): Flow<String> {
        return dataStore.data.map {
            it[THEME_MODE] ?: THEME_FOLLOW_SYSTEM
        }
    }
}